Bug 146

Bug Description:

This is a starvation bug.
More details about this bug are at POOL-146 JIRA page.

Interleaving Description:

org.apache.commons.pool.impl.GenericObjectPool:

t1  t2      public Object borrowObject(Object key) throws Exception {
                    long starttime = System.currentTimeMillis();
1   10              Latch latch = new Latch(key);
                    ...
            
                        // Add this request to the queue
2   11                  _allocationQueue.add(latch);
            
                        // Work the allocation queue, allocating idle instances and
                        // instance creation permits in request arrival order
3   12                  allocate();
                    }
                    ...
7   17              if (null == latch.getPair()) {
                        ...
                        switch(whenExhaustedAction) {
                            ...
8   18                      case WHEN_EXHAUSTED_BLOCK:
                                try {
                                    synchronized (latch) {
                                        if (maxWait <= 0) {
9   19                                      latch.wait();
                    ...
            }

            private void allocate() {
                ...
                    for (;;) {
4   13                  if (!_allocationQueue.isEmpty()) {
                            // First use any objects in the pool to clear the queue
5   14                      Latch latch = (Latch) _allocationQueue.getFirst();
    15                      ObjectQueue pool = (ObjectQueue)(_poolMap.get(latch.getkey()));
                            if (null == pool) {
                                pool = new ObjectQueue();
                                _poolMap.put(latch.getkey(), pool);
                                _poolList.add(latch.getkey());
                            }
                            latch.setPool(pool);
6   16                      if (!pool.queue.isEmpty()) {
                                ...
                            }
                ...
            }
	

Precondition: _maxActive=N. N objects have been borrowed from pool with key "A". But no objects are borrowed from pool with key "B". Exhausted action is set to block.

a) thread 1 borrows an object from pool with key "A". Latch A is created at 1 and added to allocation queue at 2. Now _allocationQueue has latch A at the head.
b) thread 1 is blocked at 9 according to the exhausted action.
c) thread 2 borrows an object from pool with key "B". Latch B is created at 10 and added into the rear of allocation queue at 11. Now _allocationQueue has latch A at head and latch B at rear.
d) thread 2 calls allocate at 12 and comes to 14 due to _allocationQueue is not empty. The head of _allocationQueue, which is latch A is fetched at 14.
e) pool with key "A" which is exhausted is fetched at 15. thread 2 is about to borrow object from pool "B", but latch B has no chance to be dealt until latch A is removed from _allocationQueue. So thread 2 is blocked at 19.


How To Reproduce:

This bug is reproduced under pool 1.5 and JDK 1.6.0_33.
Execute the following scripts to run the test to reproduce the bug (assume the location of the pool test project is pool_test_home).

Linux:
${pool_test_home}/scripts/146.sh [--monitoroff]
Windows:
%pool_test_home%\scripts\146.bat [--monitoroff]

Example:
Use monitor to report and terminate the program when deadlock happens:
${pool_test_home}/scripts/146.sh

Turn off monitor:
${pool_test_home}/scripts/146.sh --monitoroff

Option Function
--monitoroff, -mo Turn off to stop reporting bug messages and ending program when test
runs into the expected concurrency bug which is a forever waiting.
User has to terminate the program manually when this option is set.